//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.ComponentModel;
using System.Data;
using System.Threading;
using System.Windows;
using System.Workflow.ComponentModel;
using TridentChartActivities;
using Activity = System.Workflow.ComponentModel.Activity;

namespace Microsoft.Research.ScientificWorkflow.Activities
{
    [Name("Show New Chart from a DataTable", "Display DataTable Chart")]
    [Description("Displays a chart in a new window of the data passed in from a DataTable input.")]
    [WorkflowCategory("Chart")]
    public class ChartDataTable : Activity
    {
        /// <summary>
        /// The host window.
        /// </summary>
        private Window hostWin;

        #region Dependency Properties

        public static System.Workflow.ComponentModel.DependencyProperty InputDataTableProperty =
            System.Workflow.ComponentModel.DependencyProperty.Register("InputDataTable",
            typeof(DataTable), typeof(ChartDataTable), new System.Workflow.ComponentModel.PropertyMetadata(null));

        [RequiredInputParam]
        [Name("Input DataTable", "DataTable")]
        [Description("The input data to chart.")]
        public DataTable InputDataTable
        {
            get
            {
                return ((DataTable)(base.GetValue(ChartDataTable.InputDataTableProperty)));
            }
            set
            {
                base.SetValue(ChartDataTable.InputDataTableProperty, value);
            }
        }

        public static System.Workflow.ComponentModel.DependencyProperty ChartTypeProperty =
            System.Workflow.ComponentModel.DependencyProperty.Register("ChartType",
            typeof(string), typeof(ChartDataTable), new System.Workflow.ComponentModel.PropertyMetadata("ColumnSeries"));

        [OptionalInputParam]
        [Name("Chart Type")]
        [Description("The inital chart type. Possible values include: Bar Chart, Line Chart, Pie Chart, and many more.")]
        public string ChartType
        {
            get
            {
                return ((string)(base.GetValue(ChartDataTable.ChartTypeProperty)));
            }
            set
            {
                base.SetValue(ChartDataTable.ChartTypeProperty, value);
            }
        }

        public static System.Workflow.ComponentModel.DependencyProperty TitleProperty =
            System.Workflow.ComponentModel.DependencyProperty.Register("Title",
            typeof(string), typeof(ChartDataTable), new System.Workflow.ComponentModel.PropertyMetadata("Chart"));

        [OptionalInputParam]
        [Name("Title")]
        [Description("The title of the chart, also shown in the title bar of the window containing the chart.")]
        public string Title
        {
            get
            {
                return ((string)(base.GetValue(ChartDataTable.TitleProperty)));
            }
            set
            {
                base.SetValue(ChartDataTable.TitleProperty, value);
            }
        }

        public static System.Workflow.ComponentModel.DependencyProperty WindowHeightProperty =
            System.Workflow.ComponentModel.DependencyProperty.Register("WindowHeight",
            typeof(int), typeof(ChartDataTable), new System.Workflow.ComponentModel.PropertyMetadata(400));

        [OptionalInputParam]
        [Name("Window Height", "Height")]
        [Description("The height of the window that displays the chart.")]
        public int WindowHeight
        {
            get
            {
                return ((int)(base.GetValue(ChartDataTable.WindowHeightProperty)));
            }
            set
            {
                base.SetValue(ChartDataTable.WindowHeightProperty, value);
            }
        }

        public static System.Workflow.ComponentModel.DependencyProperty WindowWidthProperty =
            System.Workflow.ComponentModel.DependencyProperty.Register("WindowWidth",
            typeof(int), typeof(ChartDataTable), new System.Workflow.ComponentModel.PropertyMetadata(400));

        [OptionalInputParam]
        [Name("Window Width", "Width")]
        [Description("The width of the window that displays the chart.")]
        public int WindowWidth
        {
            get
            {
                return ((int)(base.GetValue(ChartDataTable.WindowWidthProperty)));
            }
            set
            {
                base.SetValue(ChartDataTable.WindowWidthProperty, value);
            }
        }

        public static System.Workflow.ComponentModel.DependencyProperty ArchiveChartResultsProperty =
            System.Workflow.ComponentModel.DependencyProperty.Register("ArchiveChartResults",
            typeof(bool), typeof(ChartDataTable), new System.Workflow.ComponentModel.PropertyMetadata(true));

        #endregion

        /// <summary>
        /// Initialize chart data table.
        /// </summary>
        public ChartDataTable()
        {
        }

        /// <summary>
        /// Overrides the activity execute.
        /// </summary>
        /// <param name="executionContext"></param>
        /// <returns></returns>
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            // We need the window we show to operate in its own STA thread
            Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
            newWindowThread.SetApartmentState(ApartmentState.STA);
            newWindowThread.Start();
            newWindowThread.Join();

            return ActivityExecutionStatus.Closed;
        }

        /// <summary>
        /// On launch of the new window.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void NewWindowHandler(object sender, RoutedEventArgs e)
        {
            Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
            newWindowThread.SetApartmentState(ApartmentState.STA);
            newWindowThread.Start();
        }

        /// <summary>
        /// Thread start code.
        /// </summary>
        private void ThreadStartingPoint()
        {
            try
            {
                InitializeChartPopUp();
                System.Windows.Threading.Dispatcher.Run();
            }
            catch (Exception)
            {
                // Note: Exception will not occur if the activity is executed using TrayApp
            }
        }

        /// <summary>
        /// Initialize the chart.
        /// </summary>
        private void InitializeChartPopUp()
        {
            if (this.hostWin != null)
            {
                this.hostWin.Close();
            }

            this.hostWin = new Window();
            this.hostWin.Closed += new EventHandler(this.OnChartClosed);
            this.hostWin.Width = WindowWidth;
            this.hostWin.Height = WindowHeight;
            this.hostWin.HorizontalAlignment = HorizontalAlignment.Stretch;
            this.hostWin.HorizontalContentAlignment = HorizontalAlignment.Stretch;
            this.hostWin.Title = Title;
            this.hostWin.ShowInTaskbar = false;

            TridentChartControl chartControl = new TridentChartControl(this.InputDataTable);
            this.hostWin.Content = chartControl;

            this.hostWin.Show();
        }
        
        /// <summary>
        /// Handle the window close message to kill the thread 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnChartClosed(object sender, EventArgs e)
        {
            Thread.CurrentThread.Abort();
        }
    }
}
